package org.wattdepot.gdata.kukuicup.updater.powermeter;

import java.net.URL;
import java.util.Calendar;
import java.util.List;
import javax.xml.datatype.XMLGregorianCalendar;
import org.wattdepot.client.WattDepotClient;
import org.wattdepot.gdata.kukuicup.service.GDataBatchRequest;
import org.wattdepot.gdata.kukuicup.service.GDataService;
import org.wattdepot.gdata.kukuicup.service.WattDepotService;
import org.wattdepot.gdata.kukuicup.updater.BaselineView;
import org.wattdepot.gdata.kukuicup.updater.GDataTask;
import org.wattdepot.resource.sensordata.jaxb.SensorData;
import org.wattdepot.util.tstamp.Tstamp;

/**
 * Implements the task to obtain the current power level every few seconds. 
 * @author Philip Johnson
 */
public class PowerMeterTask extends GDataTask {

  /** The current baseline power for this source and hour. */ 
  int currBaseline = 0;
  /** The view of the baseline (energy) data for this source. */
  BaselineView baselineView;
  
  /**
   * Creates the task that gets woken up regularly (typically every 15 seconds). 
   * @param wattDepotService The WattDepot service configuration data. 
   * @param gdataService The gdata service configuration data.
   * @param spreadsheetURL The URL to the spreadsheet containing the data.
   * @param sourceName The WattDepot source of interest.
   * @param isVirtual True if the source is virtual.
   * @param row The row in the spreadsheet that this source's data appears in.
   */
  public PowerMeterTask(WattDepotService wattDepotService, GDataService gdataService, 
      URL spreadsheetURL, String sourceName, boolean isVirtual, int row) {
    super(wattDepotService, gdataService, spreadsheetURL, sourceName, row, "PowerMeter",
        isVirtual);
    this.baselineView = new BaselineView(gdataService);
  }
  
  /**
   * Return the baseline level of consumption for this source at this moment in time. 
   * @return The baseline level of consumption.
   */
  public String getBaselinePower() {
    XMLGregorianCalendar now = Tstamp.makeTimestamp();
    int minuteOfHour = now.toGregorianCalendar().get(Calendar.MINUTE);
    // only compute the baseline power if it's zero (needs initialization) or during the first 
    // minute of each hour when the baseline actually changes. 
    if ((currBaseline == 0) || (minuteOfHour == 1)) {
      int dayOfWeek = now.toGregorianCalendar().get(Calendar.DAY_OF_WEEK);
      List<Integer> baselines = baselineView.getHourlyBaselines(sourceName, dayOfWeek);
      int hourOfDay = now.toGregorianCalendar().get(Calendar.HOUR_OF_DAY);
      this.currBaseline = baselines.get(hourOfDay);
    }
    return String.valueOf(this.currBaseline);
  }

  /**
   * Retrieve the power data from WattDepot and place it into the GData spreadsheet.
   */
  @Override
  public void run() {
    WattDepotClient client = this.wattDepotService.getClient();
    try {
      // We get the following values differently depending on whether the source is virtual.
      String power; 
      String powerTimestamp;
      
      startWattDepotTiming();
      if (isVirtual) {
        int powerInt = (int)client.getLatestPowerConsumed(sourceName);
        power = String.valueOf(powerInt);
        // With virtual sources, the timestamp is the time we queried.
        powerTimestamp = gdataService.makeLastUpdate();
      }
      else {
        SensorData data = client.getLatestSensorData(sourceName);
        double powerDouble = data.getPropertyAsDouble("powerConsumed");
        power = String.valueOf((int)powerDouble);
        // With non-virtual sources, the timestamp is the timestamp on the data.
        powerTimestamp = gdataService.makeLastUpdate(data.getTimestamp());
      }
      stopWattDepotTiming();
      
      // Now update the spreadsheet.
      startGDataTiming();
      GDataBatchRequest request = new GDataBatchRequest(gdataService, spreadsheetURL);
      // Update the lastUpdate cell and the power cell
      request.addRequest(this.row, 2, powerTimestamp);
      request.addRequest(this.row, 3, power);
      request.addRequest(this.row, 4, getBaselinePower());
      request.sendRequest();
      stopGDataTiming();
      printTaskResults(power, "watts", powerTimestamp);
    }
    catch (Exception e) {
      System.out.format("%s PowerMeterTask: Problem retrieving power for source %s: %s%n", 
          getTimestamp(), sourceName, e.getMessage());
      e.printStackTrace();
    }
  }
}
